/**
 *    @file       udpclient.h
 *
 *    @brief      
 *
 *    @details
 *
 *    @version    1.0
 *    @date       02/18/2014 10:13:38 AM
 *
 *    @author     Theophilus (), wangtf418@gmail.com
 */
#include <string>
#include "sockbase.h"
#include "toolkit.h"
#include "basecommand.h"
#include "buffermgr.h"

#define UDPCLIENT_BUF_LEN 4096

template<typename _Treqhead, typename _Treqbody, typename _Treshead, typename _Tresbody>
class udpclient
{
public:
	udpclient(const std::string &srvip, bf_ushort_t srvport, const std::string &bindip = "127.0.0.1", bf_ushort_t bindport = 0)
		: m_socket(srvip, srvport, bindip, bindport)
	{

	}

	virtual ~udpclient()
	{

	}

public:
	virtual bf_int_t init()
	{
		return m_socket.init();
	}

public:
	virtual bf_int_t send_and_recv(_Treqhead &reqhead, _Treqbody &reqbody, bf_time_t timeout = 5000, bf_uint32_t exbuflen = 0)
	{
		reqhead.set_bodylen(reqbody.get_size());
		bf_uint32_t buflen = reqhead.get_cmdlen();
		if (buflen == 0) return BF_ERROR;

		bf_char_t *buf = new bf_char_t[buflen + exbuflen];
		buffermgr reqbufmgr(buf, buflen);

		bf_int_t ret = reqhead.encode(reqbufmgr);
		if (ret != BF_OK) return BF_ERROR;

		ret = reqbody.encode(reqbufmgr);
		if (ret != BF_OK) return BF_ERROR;

		bf_uint32_t newbuflen = 0;
		bf_char_t *newbuf = process_send_buf(reqbufmgr.get_buf(), reqbufmgr.get_buflen(), newbuflen);
		if (!newbuf || newbuflen == 0) return BF_ERROR;
		if (newbuf != reqbufmgr.get_buf())
		{
			reqbufmgr.reset_buf(newbuf, newbuflen);
		}
		bf_int_t sendlen = m_socket.sendto(newbuf, newbuflen, timeout);
		if (sendlen <= 0) return BF_ERROR;

		bf_int_t recvlen = m_socket.recvfrom(m_recvbuf, UDPCLIENT_BUF_LEN, timeout);
		if (recvlen <= 0) return BF_ERROR;

		buffermgr resbufmgr(m_recvbuf, recvlen, 0);
		newbuf = process_recv_buf(m_recvbuf, recvlen, newbuflen);
		if (newbuf != m_recvbuf)
		{
			resbufmgr.reset_buf(newbuf, newbuflen);
			resbufmgr.set_delete_flag(1);
		}

		_Treshead reshead;
		_Tresbody resbody;
		ret = reshead.decode(resbufmgr);
		if (ret != BF_OK) return BF_ERROR;
		ret = resbody.decode(resbufmgr);
		if (ret != BF_OK) return BF_ERROR;

		ret = process(reqhead, reqbody, reshead, resbody);
		if (ret != BF_OK) return BF_ERROR;
		return BF_OK;
	}

protected:
	virtual bf_char_t * process_recv_buf(bf_char_t *buf, bf_uint32_t buflen, bf_uint32_t &newbuflen)
	{
		newbuflen = buflen;
		return buf;
	}

	virtual bf_char_t * process_send_buf(bf_char_t *buf, bf_uint32_t buflen, bf_uint32_t &newbuflen)
	{
		newbuflen = buflen;
		return buf;
	}
	virtual bf_int_t process(_Treqhead &reqhead, _Treqbody &reqbody, _Treshead &reshead, _Tresbody &resbody)
	{
		return 0;
	}

protected:
	udpclient_socket m_socket;
	bf_char_t m_recvbuf[UDPCLIENT_BUF_LEN];
};

